Skip to content

Make LazyCell<T, F> and LazyLock<T, F> covariant in both T and F #159838

Open
WaffleLapkin wants to merge 2 commits into
rust-lang:mainfrom
WaffleLapkin:covariant-lazies
Open

Make LazyCell<T, F> and LazyLock<T, F> covariant in both T and F #159838
WaffleLapkin wants to merge 2 commits into
rust-lang:mainfrom
WaffleLapkin:covariant-lazies

Conversation

@WaffleLapkin

@WaffleLapkin WaffleLapkin commented Jul 24, 2026

Copy link
Copy Markdown
Member

See explanation for why it's valid that I wrote as a comment in LazyCell:

// It is non-obvious why `LazyCell` can be covariant in both `T` and `F`
// (and thus use `CovariantUnsafeCell`)...
//
// # `F`
//
// `F` is the easier to explain one; The state only ever transitions *out* of `Uninit(F)`
// (to either `Poisoned` or `Init(T)`), and never into it. In other words `F` is only ever
// read, not written.
//
// One could imagine `LazyCell` implemented as
// ```
// struct {
// state: UnsafeCell<Uninit | Init(T) | Poisoned>,
// f: ManuallyDrop<F>,
// }
// ```
// which would make it "obviously" covariant in `F`.
//
// **NOTE**: the important invariant here is that we never allow writing `F` through
// `&LazyCell`.
//
// # `T`
//
// Why `LazyCell` can be covariant in `T` is even more subtle. We do allow writing `T` through
// a `&LazyCell`, which would normally force us to make `LazyCell` invariant in `T`. However,
// the only value that we allow writing is one returned by `F`... and we don't allow changing
// `F`. So even if a user gets a `&LazyCell<LessrestrictedVersionOfT>`, they cannot write the
// `LessrestrictedVersionOfT` through it.
//
// **NOTE**: the important invariants here are that
// 1. `T` can only be written through `&LazyCell<T, F>` by being returned from `F`
// 2. `F` cannot be overwritten after `LazyCell` creation
//
// # Conclusion
//
// `LazyCell` can be covariant in both `T` and `F`... provided the non-local invariants which
// are listed above.

r? libs-api

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 24, 2026
@WaffleLapkin WaffleLapkin changed the title Make LazyCell<T, F> and `LazyLock<T, F> covariant in both T and F Make LazyCell<T, F> and LazyLock<T, F> covariant in both T and F Jul 24, 2026
@WaffleLapkin
WaffleLapkin marked this pull request as ready for review July 27, 2026 12:35
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 27, 2026
@rustbot

rustbot commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants